package com.gsp.gspframework.helper;

import com.gsp.gspframework.annotation.Aspect;
import com.gsp.gspframework.proxy.Proxy;
import com.gsp.gspframework.proxy.ProxyAspect;
import com.gsp.gspframework.proxy.ProxyManager;
import com.gsp.gspframework.proxy.TransactionalProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.*;
import java.util.stream.Collectors;

public final class AopHelper {
    private static final Logger log = LoggerFactory.getLogger(AopHelper.class);

    static {
        try {
            Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
            Map<Class<?>, List<Proxy>> targetProxy = createTargetMap(proxyMap);
            for (Map.Entry<Class<?>, List<Proxy>> target : targetProxy.entrySet()) {
                 BeanHelper.setBean(target.getKey(), ProxyManager.createProxy(target.getKey(),target.getValue()));
            }
        } catch (Exception e) {
            log.error("aop failure", e);
        }
    }

    private static Set<Class<?>> createTargetClassSet(Aspect aspect) {
        Class<? extends Annotation> annotation = aspect.value();
        if (annotation != null && !annotation.equals(Aspect.class)) {
            return ClassHelper.getClassSetByAnnotation(annotation);
        } else {
            return new HashSet<>();
        }
    }

    private static Map<Class<?>, Set<Class<?>>> createProxyMap() throws Exception {
        Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<>();
        Set<Class<?>> proxyClzSet = ClassHelper.getClassSetBySuper(ProxyAspect.class);
        /*for (Class<?> clz : proxyClzSet) {
            if (clz.isAnnotationPresent(Aspect.class)) {
                Aspect aspect = clz.getAnnotation(Aspect.class);
                Set<Class<?>> targetClzSet = createTargetClassSet(aspect);
                proxyMap.put(clz, targetClzSet);
            }
        }
        return proxyMap;*/
        proxyMap.putAll( proxyClzSet.stream().filter(clz -> clz.isAnnotationPresent(Aspect.class)).collect(Collectors.toMap(clz -> clz, clz -> createTargetClassSet(clz.getAnnotation(Aspect.class)))));
        Set<Class<?>> serviceSet = ClassHelper.getServiceClassSet();
        proxyMap.put(TransactionalProxy.class,serviceSet);
        return proxyMap;
    }

    private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
        Map<Class<?>, List<Proxy>> resultMap = new HashMap<>();
        for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
            Set<Class<?>> targetClassSet = proxyEntry.getValue();
            Proxy proxy = (Proxy) proxyEntry.getKey().newInstance();
            for (Class<?> targetClass : targetClassSet) {
                if (resultMap.containsKey(targetClass)) {
                    resultMap.get(targetClass).add(proxy);
                } else {
                    List<Proxy> proxyList = new ArrayList<>();
                    proxyList.add(proxy);
                    resultMap.put(targetClass, proxyList);
                }
            }
        }
        return resultMap;
    }

}
